10.8 プログラムと手続 [大部分 5.3]
-
CONTAINS
文の後に空の内部副プログラム部分、モジュール副プログラム部分、 及び型束縛手続部分の記述が許されるようになりました。 型束縛手続部分の場合では(特に効果のない)PRIVATE
文が (指定する必要のない)CONTAINS
文の後に許されるようになりました。 -
[6.0]
内部手続が実引数として渡せます。また手続きポインタへ代入もできます。
内部手続が仮引数経由もしくは手続きポインタ経由で実行された場合に、
親手続きの局所変数へのアクセスが可能となりました。
手続きポインタの場合には、ポインタは親手続が復帰するまでの間のみ有効です。
(これは局所変数がそれ以降存在しなくなるからです)
例)
SUBROUTINE mysub(coeffs) REAL,INTENT(IN) :: coeffs(0:) ! Coefficients of polynomial. REAL integral integral = integrate(myfunc,0.0,1.0) ! Integrate from 0.0 to 1.0. PRINT *,'Integral =',integral CONTAINS REAL FUNCTION myfunc(x) RESULT(y) REAL,INTENT(IN) :: x INTEGER i y = coeffs(UBOUND(coeffs,1)) DO i=UBOUND(coeffs,1)-1,0,-1 y = y*x + coeffs(i) END DO END FUNCTION END SUBROUTINE
-
Fortran 2008のルールが総称解決と総称内手続のあいまいさの判断に使われるようになりました。
このルールでは:
- 仮手続は仮引数と区別が可能です。
-
ALLOCATABLE
仮変数はINTENT(IN)
を持つPOINTER
仮変数と区別可能です。
- [6.0] 遊離状態のポインタ及び割付られていない割付け変数は省略可能な非割付、非ポインタ仮引数に対しての実引数として渡す事ができます。 この場合実引数が存在していないかのように処理されます。
-
[5.3.1]
非純粋要素別処理手続は
IMPURE
キーワードを用いてが定義可能です。 非純粋要素別処理手続は要素別であるが故の制限(例えばすべての引数がスカラでなければならない)がありますが、“純粋”に関しても制限はありません。 これは非純粋要素別処理手続きに副作用があり得る事と、入出力及びSTOP
文を含み得る事を意味します。 例)Impure Elemental Integer Function checked_addition(a,b) Result(c) Integer,Intent(In) :: a,b If (a>0 .And. b>0) Then If (b>Huge(c)-a) Stop 'Positive Integer Overflow' Else If (a<0 .And. b<0) Then If ((a+Huge(c))+b<0) Stop 'Negative Integer Overflow' End If c = a + b End Function
引数が配列の場合、それぞれの成分に対して非純粋手続きが配列成分順に適用されます。 (これは特に順番が定められていない純粋要素別手続きとは異なります) 非純粋手続きは手続きが純粋でなければならない状況(例:FORALL
構文内)では参照できません。非純粋要素別手続きはおそらく最終手続きと(入出力が許されているという理由により)デバッグ時に最も有用です。
-
[6.0]
純粋手続きの引数が
VALUE
属性を持つ場合、どのINTENT
属性も必要ありません。 例)PURE SUBROUTINE s(a,b) REAL,INTENT(OUT) :: a REAL,VALUE :: b a = b END SUBROUTINE
しかしながら、利用者定義代入サブルーチンの二番目の引数と利用者定義演算のすべての引数はこの限りではなく、
VALUE
属性を持つ場合でもINTENT(IN)
属性を指定しなければなりません。 -
[5.3.1]
内部手続及びモジュール手続において、
END文の
FUNCTION
及びSUBROUTINE
キーワードが省略可能となりました。(手続名も指定しない場合のみ) 今までは外部手続でのみ省略可能でした。 -
ENTRY
文は削除予定機能として扱われます。 - [1.0] プログラム内の行がセミコロンで始まっても良くなりました。
-
[6.2] 結合名を持つ外部手続きの名前が大域識別子ではなく局所識別子として取り扱われるようになりました。
これが意味するのは、例えば以下のようなコードが標準準拠になったという事です。
SUBROUTINE sub() BIND(C,NAME='one') PRINT *,'one' END SUBROUTINE SUBROUTINE sub() BIND(C,NAME='two') PRINT *,'two' END SUBROUTINE PROGRAM test INTERFACE SUBROUTINE one() BIND(C) END SUBROUTINE SUBROUTINE two() BIND(C) END SUBROUTINE END INTERFACE CALL one CALL two END PROGRAM
-
[6.2]
NAME=
指示子を持たない場合に限り、 内部手続がBIND(C)
属性であっても許容されます。 このような手続きはCと相互運用可能ですが(NAME=''
で指定するような)結合名を持ちません。 -
[6.2]
VALUE
属性を持つ仮引数が配列であっても許容されます。 また非定数及び/又は1ではない長さのCHARACTER
型であっても許容されます。 (ALLOCATABLE
又はPOINTER
属性を持つ事は依然として許容されません。 また共配列も許容されません。)結果としては実引数の複製が作られ、仮引数はその複製と結合されます。 仮引数への変更は実引数に影響を及ぼしません。 例えば
PROGRAM value_example_2008 INTEGER :: a(3) = [ 1,2,3 ] CALL s('Hello?',a) PRINT '(7X,3I6)',a CONTAINS SUBROUTINE s(string,j) CHARACTER(*),VALUE :: string INTEGER,VALUE :: j(:) string(LEN(string):) = '!' j = j + 1 PRINT '(7X,A,3I6)',string,j END SUBROUTINE END PROGRAM
は以下を出力します。Hello! 2 3 4 1 2 3
-
[7.0]
サブモジュールは、個別モジュール手続きと共に、Fortranプログラムを構築する追加の方法を提供します。
“個別モジュール手続き”は、引用仕様がモジュール宣言部で宣言され、その定義がモジュール自体もしくはそのモジュールのサブモジュールのいずれかで提供される手続きです。 個別モジュール手続きの引用仕様は、引用仕様本体の手続接頭句で
MODULE
キーワードを用いて宣言されます。 例)INTERFACE MODULE RECURSIVE SUBROUTINE sub(x,y) REAL,INTENT(INOUT) :: x,y END SUBROUTINE END INTERFACE
個別モジュール手続きの引用仕様の重要な側面は、他の引用仕様本体とは異なり、IMPORT
文を必要とせずに親子結合によってモジュールへアクセスする点です。 例)INTEGER,PARAMETER :: wp = SELECTED_REAL_KIND(15) INTERFACE MODULE REAL(wp) FUNCTION f(a,b) REAL(wp) a,b END FUNCTION END INTERFACE
個別モジュール手続きの最終的な定義は、モジュール、サブモジュールに関わらず、引用仕様の宣言とまったく同じ特性、同じ仮引数名、同じ名前結果変数名(関数の場合)、 同じbinding-name(BIND(C)
を使用する場合)、そしてRECURSIVE
の場合はRECURSIVE
でなければなりません。 これを実現する方法は以下の2つがあります。-
通常の方法で手続きを定義し、すべての特性を正しく取得します。コンパイラによりチェックがなされます。
定義は手続接頭句に
MODULE
キーワードを含む必要があります。 例)... CONTAINS MODULE REAL(wp) FUNCTION f(a,b) REAL(wp)a,b f = a**2 - b**3 END FUNCTION
-
または、引用仕様全体を、
MODULE PROCEDURE
文を用いて、再宣言することなく、アクセスする事も可能です。 例)... CONTAINS MODULE PROCEDURE sub ! 引数AとBとそれらの特性、再帰サブルーチンであるという点は ! すべて引用仕様宣言から取得される。 IF (a>b) THEN CALL sub(b,-ABS(a)) ELSE a = b**2 - a END IF END PROCEDURE
submodule-stmt declaration-part [ CONTAINS module-subprogram-part ] END [ SUBMODULE [ submodule-name ] ]
初期のsubmodule-stmtの形式はSUBMODULE ( module-name [ : parent-submodule-name ] ) submodule-name
module-nameは、1つ以上の個別モジュール手続きを持つモジュールの名前です。 parent-submodule-name(存在する場合)はそのモジュールの別のサブモジュールの名前であり、 parent-submodule-name(存在する場合)はそのモジュールの別のサブモジュールの名前であり、submodule-nameは定義されているサブモジュールの名前です。 したがって、モジュールのサブモジュールはツリー構造を形成し、一連のサブモジュールは他のサブモジュールを拡張できます。 ただし、サブモジュールの名前はそのモジュール内で一意です。 この構造は、モジュール自体にすべての基礎情報(タイプ、定数、および手続き)を配置することなく、複数のサブモジュールで使用できる内部基礎情報の作成を容易にするためのものです。定義されているサブモジュールは、親子結合によって親モジュールまたはサブモジュールにアクセスします。 モジュールの要素の場合、これには
PRIVATE
要素へのアクセスが含まれます。 したがって、declaration-partで宣言する局所要素は、同じ名前を持つホスト内の要素へのアクセスをブロックします。サブモジュールによって宣言された要素(変数、型、手続き)は、そのサブモジュールに対して局所的です。 ただし、祖先モジュールで宣言され、サブモジュールで定義された個別モジュール手続きは例外です。 束縛名が引用仕様と同じである必要がある別のモジュール手続きの場合を除き、手続きは束縛名を持つことはできません。
例)
MODULE mymod INTERFACE MODULE INTEGER FUNCTION next_number() RESULT(r) END FUNCTION MODULE SUBROUTINE reset() END SUBROUTINE END INTERFACE END MODULE SUBMODULE (mymod) variables INTEGER :: next = 1 END SUBMODULE SUBMODULE (mymod:variables) functions CONTAINS MODULE PROCEDURE next_number r = next next = next + 1 END PROCEDURE END SUBMODULE SUBMODULE (mymod:variables) subroutines CONTAINS MODULE SUBROUTINE reset() PRINT *,'Resetting' next = 1 END SUBROUTINE END SUBMODULE PROGRAM demo USE mymod PRINT *,'Hello',next_number() PRINT *,'Hello again',next_number() CALL reset PRINT *,'Hello last',next_number() END PROGRAM
他のサブモジュールで使用するサブモジュール情報は、 nAG Fortranコンパイラーによってmodule
.
submodule.sub
という名前のファイルに、.mod
と同様の形式で保存されます。.mod
ファイルの作成を抑制する-nomodオプションは、.sub
ファイルの作成も抑止します。 -
通常の方法で手続きを定義し、すべての特性を正しく取得します。コンパイラによりチェックがなされます。
定義は手続接頭句に